package arch.chameleon.module.web;

import static arch.chameleon.support.constants.WebConstants.MEDIA_TYPES_JSON;
import static arch.chameleon.support.constants.WebConstants.REQ_HEADER_ACCEPT;
import static arch.chameleon.support.constants.WebConstants.REQ_HEADER_X_REQUESTED_WITH;
import static arch.chameleon.support.constants.WebConstants.REQ_TYPE_XHR;
import static arch.chameleon.support.constants.WebConstants.RSP_BODY;
import static arch.chameleon.support.constants.WebConstants.RSP_HEAD;
import static arch.chameleon.support.constants.WebConstants.RSP_MSG;
import static arch.chameleon.support.constants.WebConstants.RSP_STATUS;
import static arch.chameleon.support.constants.WebConstants.RSP_STATUS_FAILURE;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

/**
 * 自定义Spring MVC错误处理机制，使其同时支持同步及异步处理
 * 
 * modify by George
 * 
 */
public class CustomSimpleMappingExceptionResolver extends
		SimpleMappingExceptionResolver {
	@Override
	protected ModelAndView doResolveException(HttpServletRequest request,
			HttpServletResponse response, Object handler, Exception ex) {

		// Expose ModelAndView for chosen error view.
		String viewName = determineViewName(ex, request);
		if (viewName != null) {// for jsp
			if (!(request.getHeader(REQ_HEADER_ACCEPT).indexOf(MEDIA_TYPES_JSON) > -1 
					 || (request.getHeader(REQ_HEADER_X_REQUESTED_WITH) != null 
					 && request.getHeader(REQ_HEADER_X_REQUESTED_WITH).indexOf(REQ_TYPE_XHR) > -1))) {// 非异步请求判断
				log.debug("catch synchronized request exception...");
				// Apply HTTP status code for error views, if specified.
				// Only apply it if we're processing a top-level request.
				Integer statusCode = determineStatusCode(request, viewName);
				log.debug("statusCode:{}", new Object[]{statusCode});
				if (statusCode != null) {
					applyStatusCodeIfPossible(request, response, statusCode);
				}
				return getModelAndView(viewName, ex, request);
			} else {// 异步请求(json data)
				log.debug("catch asynchronized request exception...");
				Map<String, Object> model = new HashMap<String, Object>();
				
				/**
				 * 响应格式：
				 *		{
				 *  		"RSP_HEAD":{
				 *      		"RSP_STATUS":"1",
				 *      		"MSG":""
				 *  		},
				 *  		"RSP_BODY":{
				 *  			"TS_CUST_NAME":"wang_yanqin",
				 *   			"TS_CUST_ADD":"FangHuaRoad"    
				 *   		}
				 * 		}
				 **/
				
				Map<String, String> mpRspHead = new HashMap<String, String>();
				mpRspHead.put(RSP_STATUS, RSP_STATUS_FAILURE);
				mpRspHead.put(RSP_MSG, ex.getMessage());
				return new ModelAndView()
					.addObject(RSP_HEAD, mpRspHead)
					.addObject(RSP_BODY, model);
			}
		} else {
			return null;
		}
	}
	
	private transient Logger log = LoggerFactory.getLogger(this.getClass());
}
